package br.com.pucrs.aa;

import jason.environment.grid.GridWorldModel;
import jason.environment.grid.Location;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

public class StreetModel extends GridWorldModel {

	// constants for the grid objects
	public static final int OBSTACLE = 16;
	public static final int STOP = 32;

	private static Logger logger = Logger.getLogger(StreetModel.class.getName());

	private int numberOfWalkers;
	private int numberOfCoordinators;
	private boolean changedSemaphore = false;

	private ArrayList<Stop> semaphores = new ArrayList<Stop>();
	private Map<Integer, Street> agStreet = new HashMap<Integer, Street>();
	private Map<Integer, ArrayList<Location>> coordinatorArea = new HashMap<Integer, ArrayList<Location>>();

	public StreetModel(int w, int h, int nbAg) {
		super(w, h, nbAg);
	}

	public void setNumberOfCoordinators(int number) {
		this.numberOfCoordinators = number;
	}

	public void setNumberOfWalkers(int number) {
		this.numberOfWalkers = number;
	}

	public void assignAgToStreet(int agId, Street street) {
		agStreet.put(new Integer(agId), street);
	}

	//Little blue agents quadrants
	public void assignLocationsToCoordinator(int agId, ArrayList<Location> locations) {
		coordinatorArea.put(new Integer(agId), locations);
	}

	public void addStops(List<Stop> stops) {
		for (Stop stop : stops) {
			semaphores.add(stop);
		}
	}

	public synchronized boolean changeSemaphore(Direction dir1, Direction dir2, int agId) throws Exception {
		for (Stop stop : this.semaphores) {
			if (stop.getIdResponsable() == agId) {
				if (stop.getDirection() == dir1 || stop.getDirection() == dir2) {
					stop.setSemaphoreColor(Signal.GREEN);
				} else {
					stop.setSemaphoreColor(Signal.RED);
				}
			}
		}
		this.changedSemaphore = true;

		return true;
	}

	public synchronized boolean move(Direction dir, int ag) throws Exception {
		if (ag < 0) {
			logger.warning("Trying to move unknown agent!");
			return false;
		}
		Location l = getAgPos(ag);
		if (l == null) {
			logger.warning("We lost the location of agent " + (ag + 1) + "!" + this);
			return false;
		}
		Location n = null;
		switch (dir) {
		case UP:
			n = new Location(l.x, l.y - 1);
			break;
		case DOWN:
			n = new Location(l.x, l.y + 1);
			break;
		case RIGHT:
			n = new Location(l.x + 1, l.y);
			break;
		case LEFT:
			n = new Location(l.x - 1, l.y);
			break;
		}
		if (n != null && isInsideGridBounds(n)) {
			if (isFreeOfObstacle(n)) {
				// if there is not an agent there, move that agent
				if (!hasObject(AGENT, n)) {
					setAgPos(ag, n);
					return true;
				}
			}
		} else {
			//start again        	
			Street street = agStreet.get(new Integer(ag));
			if (isFreeOfObstacle(street.getBegin()) && !hasObject(AGENT, street.getBegin())) {
				setAgPos(ag, street.getBegin());
			} else {
				System.out.println("Out of grid and has an agent in the street start!");
			}
			//System.out.println("Out of grid, starting again!");
		}

		return false;
	}

	private boolean isInsideGridBounds(Location l) {
		return ((l.y >= 0 && l.y < getHeight()) && (l.x >= 0 && l.x < getWidth()));
	}

	public int getNumberOfWalkers() {
		return numberOfWalkers;
	}

	public int getNumberOfCoordinators() {
		return numberOfCoordinators;
	}

	public boolean isChangedSemaphore() {
		return changedSemaphore;
	}

	public void setChangedSemaphore(boolean changedSemaphore) {
		this.changedSemaphore = changedSemaphore;
	}

	public Map<Integer, ArrayList<Location>> getCoordinatorArea() {
		return coordinatorArea;
	}

	public void setCoordinatorArea(Map<Integer, ArrayList<Location>> coordinatorArea) {
		this.coordinatorArea = coordinatorArea;
	}

	public Map<Integer, Street> getAgStreet() {
		return agStreet;
	}

	public void setAgStreet(Map<Integer, Street> agStreet) {
		this.agStreet = agStreet;
	}

	public ArrayList<Stop> getSemaphores() {
		return semaphores;
	}

	public void setSemaphores(ArrayList<Stop> semaphores) {
		this.semaphores = semaphores;
	}

}
